package cn.centec.core.entity;

import cn.centec.core.exception.ErrorRuntimeException;
import cn.centec.core.exception.WarnRuntimeException;
import cn.centec.core.util.JsonUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;

import java.util.List;

/**
 * 描述：返回结果
 * 
 * @author 延晓磊
 *
 * @since 2016年4月10日
 */
@Data
public class Result {

	// 响应状态
	private String status;

	// 响应消息
	private String msg;

	// 响应的数据：Map/JSONObject/Object
	private Object data;

	/**
	 * 
	 * 描述：返回结果枚举
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年7月7日
	 */
	public enum ResultEnum{

		/**
		 * 成功状态(请求正常，根据结果数据data处理业务)
		 */
		SUCCESS("200","操作成功"),
		/**
		 * 业务错误状态（业务错误，非法请求等）
		 */
		ERROR("400","操作失败"),
		/**
		 * 非法请求状态（按正常流程操作不可能的操作）
		 */
		ILLEGAL("405","非法请求"),
		/**
		 * 参数异常状态(前端未做校验，需要更改前端代码)
		 */
		FAIL_JS("410","参数错误"),
		/**
		 * 服务器异常状态(后端出错，需要修改后端代码)
		 */
		FAIL("500","服务异常");

		
		//状态码
		private final String status;
		
		//状态默认消息
		private final String msg;

		ResultEnum(String status, String msg) {
			this.status = status;
			this.msg = msg;
		}

		/**
		 * 
		 * 功能描述：状态码
		 */
		public String getStatus() {
			return status;
		}
		/**
		 * 
		 * 功能描述：状态默认消息
		 */
		public String getMsg() {
			return msg;
		}
	}
	
	/**
	 * 描述： 常用data键常量
	 *
	 * @author 延晓磊
	 *
	 * @since 2016年5月14日
	 */
	public static class DataKey {
		// 数字
		public static final String NUM = "num";
		// 字符串：文本值、HTML页面内容
		public static final String STR = "str";
		// 数组
		public static final String LIST = "list";
		// 布尔：0 == false; 1 = true
		public static final String BOOL = "bool";
	}
	
	// =============================== 常量Result ===================================//

	/**
	 * 成功响应(200 - 成功)
	 */
	public static final Result SUCCESS = Result.success();
	/**
	 * 是 - Bool-1(200)
	 */
	public static final Result SUCCESS_YES = Result.successBoolYes();
	/**
	 * 否 - Bool-0(200)
	 */
	public static final Result SUCCESS_NO = Result.successBoolNo();
	/**
	 * 非法请求(405 - RequestRuntimeException)
	 */
	public static final Result ILLEGAL = Result.illegal();

	// =============================== 创建Result ===================================//
	
	/**
	 * 构造响应结果
	 * 
	 */
	public Result() {
		super();
	}

	/**
	 * 构造响应结果
	 * 
	 * @param status
	 * @param msg
	 * @param data
	 */
	public Result(String status, String msg, Object data) {
		this.status = status;
		this.msg = msg;
		this.data = data;
	}

	/**
	 * 业务错误响应
	 * 
	 * @param msg 业务处理错误信息
	 * @return {status:400,msg:msg,data:null}
	 */
	public static Result error(String msg) {
		return new Result(ResultEnum.ERROR.getStatus(), msg, null);
	}

	/**
	 * 非法请求错误
	 * 
	 * @return {status:405,msg:"非法请求",data:null}
	 */
	public static Result illegal() {
		return new Result(ResultEnum.ILLEGAL.getStatus(), ResultEnum.ILLEGAL.getMsg(), null);
	}
	
	/**
	 * 请求错误响应
	 * 
	 * @param msg 非法请求信息
	 * @return {status:405,msg:msg,data:null}
	 */
	public static Result illegal(String msg) {
		return new Result(ResultEnum.ILLEGAL.getStatus(), msg, null);
	}

	/**
	 * 服务器异常响应
	 *
	 * @param msg 异常终止信息
	 * @return {status:500,msg:msg,data:null}
	 */
	public static Result fail(String msg) {
		return new Result(ResultEnum.FAIL.getStatus(), msg, null);
	}

	/**
	 * 前端错误响应
	 *
	 * @param msg 错误信息
	 * @return {status:410,msg:msg,data:null}
	 */
	public static Result failJs(String msg) {
		return new Result(ResultEnum.FAIL_JS.getStatus(), msg, null);
	}

	/**
	 * 成功响应
	 * 
	 * @return {status:200,msg:"SUCCESS",data:null}
	 */
	public static Result success() {
		return new Result(ResultEnum.SUCCESS.getStatus(), ResultEnum.SUCCESS.getMsg(), null);
	}

	/**
	 * 成功响应(多键值对类型，Object、 Map)
	 * 
	 * @param data
	 *            键值对类型结果
	 * @return {status:200,msg:"SUCCESS",data:data}
	 */
	public static Result success(Object data) {
		return new Result(ResultEnum.SUCCESS.getStatus(), ResultEnum.SUCCESS.getMsg(), data);
	}

	/**
	 * 
	 * 成功响应(键值对类型)
	 *
	 * @param key
	 *            data的键
	 * @param value
	 *            data的值
	 * @return {status:200,msg:"SUCCESS",data:{key,value}}
	 */
	public static Result success(String key, Object value) {
		JSONObject anyMap = new JSONObject(1);
		anyMap.put(key, value);
		return new Result(ResultEnum.SUCCESS.getStatus(), ResultEnum.SUCCESS.getMsg(), anyMap);
	}

	/**
	 * 成功响应(布尔类型)
	 * 
	 * @param bool  true:1,false:0
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{bool:1/0}}
	 */
	public static Result successBool(boolean bool) {
		if (bool) {
			return Result.SUCCESS_YES;
		}else {
			return Result.SUCCESS_NO;
		}
	}

	/**
	 * 成功响应(布尔类型， 1是)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{bool:1}}
	 */
	public static Result successBoolYes() {
		return success(DataKey.BOOL, 1);
	}

	/**
	 * 成功响应(布尔类型， 0否)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{bool:0}}
	 */
	public static Result successBoolNo() {
		return success(DataKey.BOOL, 0);
	}

	/**
	 * 成功响应(数组集合类型，Array)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{list:[]}}
	 */
	public static <T>Result successList(T[] list) {
		return success(DataKey.LIST, list);
	}

	/**
	 * 成功响应(数组集合类型，List、Set)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{list:[]}}
	 */
	public static Result successList(Iterable<?> list) {
		return success(DataKey.LIST, list);
	}

	/**
	 * 成功响应(Number类型)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{num:''}}
	 */
	public static Result successNum(Number num) {
		return success(DataKey.NUM, num);
	}

	/**
	 * 成功响应(String类型)
	 * 
	 * @return {status:200,msg:"SUCCESS",data:{str:''}}
	 */
	public static Result successStr(String str) {
		return success(DataKey.STR, str);
	}

	// =============================== 解析REST-Result ===================================//
	
	/**
	 * 
	 * 功能描述：判断是否响应成功
	 *
	 * @return
	 * 
	 * @author yxl
	 *
	 * @since 2016-9-20
	 */
	@JSONField(serialize=false,deserialize=false)
	public boolean isSuccess() {
		return ResultEnum.SUCCESS.getStatus().equals(this.getStatus());
	}
	
	/**
	 * 功能描述：判断是否响应错误（前缀4）
	 *
	 * @return
	 * 
	 * @author yxl
	 *
	 * @since 2016-9-20
	 */
	@JSONField(serialize=false,deserialize=false)
	public boolean isError() {
		return this.status.startsWith("4");
	}

	/**
	 * 功能描述：判断是否响应异常（前缀5）
	 *
	 * @return
	 *
	 * @author yxl
	 *
	 * @since 2016-9-20
	 */
	@JSONField(serialize=false,deserialize=false)
	public boolean isFail() {
		return ResultEnum.FAIL.getStatus().equals(this.getStatus());
	}

	/**
	 * 获取JSONObject（Map<String,Object>）类型的data
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年11月24日
	 */
	@JSONField(serialize=false,deserialize=false)
	public JSONObject getJsonData(){
		Object rdata = this.getData();
		if(rdata == null) return null;
		//默认会转换为LinkedHashMap，需要先转换成String，再转成JSON
		return JsonUtil.parseObject(JsonUtil.toString(rdata));
	}

	/**
	 * REST请求的结果校验
	 * 
	 * @return "成功/重定向"返回result，"失败/异常"抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public Result rest(){
		if (this.isSuccess()) {
			return this;
		}else if (this.isError()) {
			throw new WarnRuntimeException(this.msg);
		}else{
			throw new ErrorRuntimeException(this.msg);
		}
	}

	/**
	 * REST请求的结果校验
	 *
	 * @return 成功返回result.data，失败抛异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public <T>T getObj(Class<T> clazz){
		Object rdata = this.getData();
		if (rdata == null) return null;
		return JsonUtil.parse(JsonUtil.toString(rdata), clazz);
	}

	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回result.data，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public <T>T rest(Class<T> clazz){
		return this.rest().getObj(clazz);
	}
	
	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回JSONObject(result.data)，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public JSONObject restJson(){
		return this.rest().getJsonData();
	}

	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回result.bool，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public boolean restBool(){
		JSONObject jsonData = this.getJsonData();
		if (jsonData != null) {
			return 1 ==  jsonData.getInteger(DataKey.BOOL);
		}
		return false;
	}
	
	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回list，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public <T>List<T> restList(Class<T> clazz){
		JSONObject jsonData = this.restJson();
		if (jsonData != null) {
			JSONArray jsonArray = jsonData.getJSONArray(DataKey.LIST);
			if (jsonArray != null) {
				return jsonArray.toJavaList(clazz);
			}
		}
		return null;
	}
	
	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回str，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public String restStr(){
		JSONObject jsonData = this.restJson();
		if (jsonData != null) {
			return jsonData.getString(DataKey.STR);
		}
		return null;
	}

	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回num，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public Long restLong(){
		JSONObject jsonData = this.restJson();
		if (jsonData != null) {
			return jsonData.getLong(DataKey.NUM);
		}
		return null;
	}
	
	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回num，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public Integer restInt(){
		JSONObject jsonData = this.restJson();
		if (jsonData != null) {
			return jsonData.getInteger(DataKey.NUM);
		}
		return null;
	}
	
	/**
	 * REST请求的结果校验
	 * 
	 * @return 成功返回num，失败抛异常
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月30日
	 */
	@JSONField(serialize=false,deserialize=false)
	public Double restDouble(){
		JSONObject jsonData = this.restJson();
		if (jsonData != null) {
			return jsonData.getDouble(DataKey.NUM);
		}
		return null;
	}


}
